﻿#include "framework.h"
#include <commdlg.h>
#include "MainWindow.h"
#include "Resource.h"

// 函数声明
static void MainWindow_Delete(MainWindow*);
static void MainWindow_DoModal(MainWindow*);
static void MainWindow_OnActivate(MainWindow*, WPARAM);
static void MainWindow_OnButtonHelpClicked(MainWindow*);
static void MainWindow_OnButtonMusicClicked(MainWindow*);
static void MainWindow_OnButtonPauseClicked(MainWindow*);
static void MainWindow_OnButtonStartClicked(MainWindow*);
static void MainWindow_OnDifficultyUp(MainWindow*, int);
static void MainWindow_OnGameOver(MainWindow*, BOOL);
static BOOL MainWindow_OnKeyPressed(MainWindow*, UINT);
static void MainWindow_OnScore(MainWindow*, int);
static void MainWindow_OnTimer(MainWindow*);
static INT_PTR CALLBACK MainWindow_Proc(HWND, UINT, WPARAM, LPARAM);

/**
 * 创建主窗口。
 * @return 主窗口
 */
MainWindow* New_MainWindow() {
    DWORD style = 0;                                                        // 控件风格
    HMODULE module = GetModuleHandle(NULL);                                 // 模块
    HICON icon = LoadIcon(module, MAKEINTRESOURCE(IDI_START));              // 工具栏按钮图标
    ICONINFO iconInfo = { 0 };                                              // 图标信息
    BITMAP bmpInfo = { 0 };                                                 // 位图信息
    int iconFlag = 0;                                                       // 图标标志
    TBBUTTON tbButtons[] = {
        {0, IDC_BUTTON_START, TBSTATE_ENABLED, 0, 0, 0, 0},
        {1, IDC_BUTTON_PAUSE, 0, 0, 0, 0, 0},
        {2, IDC_BUTTON_MUSIC, TBSTATE_ENABLED, 0, 0, 0, 0},
        {3, IDC_BUTTON_HELP, TBSTATE_ENABLED, 0, 0, 0, 0},
    };                                                                      // 工具栏按钮信息
    int buttonCount = sizeof(tbButtons) / sizeof(TBBUTTON);                 // 按钮数
    int parts[STATUS_BAR_PART_COUNT] = { 0 };                               // 状态栏格宽度信息
    TCHAR text[STRING_BUF_LEN] = { 0 };                                     // 状态栏上的文字
    RECT rect = { 0 };                                                      // 矩形
    int i = 0;                                                              // 循环变量
    MainWindow* mainWindow = (MainWindow*)calloc(1, sizeof(MainWindow));    // 主窗口

    // 初始化数据
    mainWindow->mHandle = CreateDialog(NULL, MAKEINTRESOURCE(IDD_MAIN_WINDOW), NULL, MainWindow_Proc);
    SetWindowLongPtr(mainWindow->mHandle, GWLP_USERDATA, (LONG_PTR)mainWindow);
    style = WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS;
    mainWindow->mToolBar = CreateWindowEx(0, TOOLBARCLASSNAME, 0, style, 0, 0, 0, 0, mainWindow->mHandle, 0, NULL, 0);
    style = WS_CHILD | WS_VISIBLE | CCS_BOTTOM;
    mainWindow->mStatusBar = CreateStatusWindow(style, NULL, mainWindow->mHandle, 0);

    // 初始化函数
    mainWindow->doModal = MainWindow_DoModal;

    // 设置工具栏
    SendMessage(mainWindow->mToolBar, TB_ADDBUTTONS, buttonCount, (LPARAM)&tbButtons); // 工具栏添加按钮
    GetIconInfo(icon, &iconInfo);
    GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bmpInfo);
    iconFlag = bmpInfo.bmBitsPixel;
    if (iconInfo.hbmMask != NULL) {
        iconFlag |= ILC_MASK;
    }
    mainWindow->mImageList = ImageList_Create(bmpInfo.bmWidth, bmpInfo.bmHeight, iconFlag, buttonCount, 0);
    for (i = 0; i < buttonCount; i++) {
        icon = LoadIcon(module, MAKEINTRESOURCE(IDI_START + i));
        ImageList_AddIcon(mainWindow->mImageList, icon);
    }
    SendMessage(mainWindow->mToolBar, TB_SETIMAGELIST, 0, (LPARAM)mainWindow->mImageList);  // 设置工具栏图标列表
    SendMessage(mainWindow->mToolBar, TB_ADDBUTTONS, buttonCount, (LPARAM)&tbButtons);      // 设置工具栏按钮
    SendMessage(mainWindow->mToolBar, TB_AUTOSIZE, 0, 0);                                   // 设置工具栏尺寸为不自动变化

    // 设置状态栏
    GetWindowRect(mainWindow->mHandle, &rect);
    parts[0] = (rect.right - rect.left) / STATUS_BAR_PART_COUNT;
    parts[1] = rect.right - rect.left;
    SendMessage(mainWindow->mStatusBar, SB_SETPARTS, STATUS_BAR_PART_COUNT, (LPARAM)parts); // 设置状态栏的格的宽度
    LoadString(NULL, IDS_DIFFICULTY, text, STRING_BUF_LEN);
    SendMessage(mainWindow->mStatusBar, SB_SETTEXT, 0, (LPARAM)text);                       // 设置状态栏第1格的文字
    LoadString(NULL, IDS_SCORE, text, STRING_BUF_LEN);
    SendMessage(mainWindow->mStatusBar, SB_SETTEXT, 1, (LPARAM)text);                       // 设置状态栏第2格的文字

    // 创建游戏区域
    GetWindowRect(mainWindow->mToolBar, &rect);
    mainWindow->mGameBoard = New_GameBoard(mainWindow->mHandle, 0, rect.bottom - rect.top, GAME_BOARD_WIDTH, GAME_BOARD_HEIGHT);

    // 创建游戏
    mainWindow->mGame = New_Game(mainWindow->mHandle, mainWindow->mGameBoard->mDrawer, mainWindow->mGameBoard->mHandle);

    return mainWindow;
}

/**
 * 删除主窗口。
 * @param mainWindow    主窗口
 */
static void MainWindow_Delete(MainWindow* mainWindow) {
    // 删除游戏
    mainWindow->mGame->deleteSelf(mainWindow->mGame);

    // 销毁控件
    DeleteObject(mainWindow->mImageList);
    DestroyWindow(mainWindow->mStatusBar);
    DestroyWindow(mainWindow->mToolBar);

    // 销毁窗口
    DestroyWindow(mainWindow->mHandle);

    // 释放内存
    free(mainWindow);
}

/**
 * 以模态显示窗口。
 * @param mainWindow    主窗口
 */
static void MainWindow_DoModal(MainWindow* mainWindow) {
    MSG msg = { 0 };
    BOOL handledKeyPress = FALSE;

    // 显示窗口
    ShowWindow(mainWindow->mHandle, SW_SHOW);

    // 窗口事件循环
    while (GetMessage(&msg, NULL, 0, 0)) {
        if (msg.message == WM_KEYDOWN) {
            handledKeyPress = MainWindow_OnKeyPressed(mainWindow, msg.wParam);
        }
        if (!handledKeyPress) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        handledKeyPress = FALSE;
    }
}

/**
 * 窗口活动事件的响应函数。
 * @param mainWindow    主窗口
 * @param wParam        为 WA_INACTIVE 则表示窗口进入不活动状态
 */
static void MainWindow_OnActivate(MainWindow* mainWindow, WPARAM wParam) {
    if (mainWindow == NULL) {
        return;
    }
    if (mainWindow->mGame->mStatus == PLAYING && wParam == WA_INACTIVE) {
        MainWindow_OnButtonPauseClicked(mainWindow);
    }
}

/**
 * "帮助"按钮的单击响应函数。
 * @param mainWindow    主窗口
 */
static void MainWindow_OnButtonHelpClicked(MainWindow* mainWindow) {
    TCHAR text[STRING_BUF_LEN] = { 0 };
    LoadString(NULL, IDS_HELP_TEXT, text, STRING_BUF_LEN);
    MessageBox(mainWindow->mHandle, text, _T(" "), MB_ICONINFORMATION);
}

/**
 * "播放音乐"按钮的单击响应函数。
 * @param mainWindow    主窗口
 */
static void MainWindow_OnButtonMusicClicked(MainWindow* mainWindow) {
    BOOL playingMusic = mainWindow->mGame->playMusic(mainWindow->mGame);
    SendMessage(mainWindow->mToolBar, TB_CHECKBUTTON, IDC_BUTTON_MUSIC, playingMusic);
}

/**
 * "暂停"按钮的单击响应函数。
 * @param mainWindow    主窗口
 */
static void MainWindow_OnButtonPauseClicked(MainWindow* mainWindow) {
    mainWindow->mGame->pause(mainWindow->mGame);
    SendMessage(mainWindow->mToolBar, TB_CHECKBUTTON, IDC_BUTTON_PAUSE, mainWindow->mGame->mStatus == PAUSED);
}

/**
 * "开始"按钮的单击响应函数。
 * @param mainWindow    主窗口
 */
static void MainWindow_OnButtonStartClicked(MainWindow* mainWindow) {
    TCHAR text[STRING_BUF_LEN] = { 0 };     // 状态栏上显示的文字
    TCHAR number[STRING_BUF_LEN] = { 0 };   // 数字

    // 游戏开始
    mainWindow->mGame->start(mainWindow->mGame);

    // 设置按钮状态
    SendMessage(mainWindow->mToolBar, TB_ENABLEBUTTON, IDC_BUTTON_PAUSE, TRUE);
    SendMessage(mainWindow->mToolBar, TB_CHECKBUTTON, IDC_BUTTON_PAUSE, FALSE);

    // 设置状态栏显示的文字
    LoadString(NULL, IDS_DIFFICULTY, text, STRING_BUF_LEN);
    _itot_s(1, number, STRING_BUF_LEN, 10);
    _tcscat_s(text, STRING_BUF_LEN, number);
    SendMessage(mainWindow->mStatusBar, SB_SETTEXT, 0, (LPARAM)text);

    LoadString(NULL, IDS_SCORE, text, STRING_BUF_LEN);
    _itot_s(0, number, STRING_BUF_LEN, 10);
    _tcscat_s(text, STRING_BUF_LEN, number);
    SendMessage(mainWindow->mStatusBar, SB_SETTEXT, 1, (LPARAM)text);
}

/**
 * 难度增加事件的响应函数。
 * @param mainWindow    主窗口
 * @param difficulty    难度
 */
static void MainWindow_OnDifficultyUp(MainWindow* mainWindow, int difficulty) {
    TCHAR text[STRING_BUF_LEN] = { 0 };
    TCHAR temp[STRING_BUF_LEN] = { 0 };

    LoadString(NULL, IDS_DIFFICULTY, text, STRING_BUF_LEN);
    _itot_s(difficulty, temp, STRING_BUF_LEN, 10);
    _tcscat_s(text, STRING_BUF_LEN, temp);
    SendMessage(mainWindow->mStatusBar, SB_SETTEXT, 1, (LPARAM)text);
}

/**
 * 游戏结束事件的响应函数。
 * @param mainWindow    主窗口
 * @param isWon         胜利则为 TRUE，否则为 FALSE
 */
static void MainWindow_OnGameOver(MainWindow* mainWindow, BOOL isWon) {
    TCHAR text[STRING_BUF_LEN] = { 0 };

    if (isWon) {
        LoadString(NULL, IDS_WON, text, STRING_BUF_LEN);
    } else {
        LoadString(NULL, IDS_LOST, text, STRING_BUF_LEN);
    }
    MessageBox(mainWindow->mHandle, text, _T(" "), MB_ICONINFORMATION);

    SendMessage(mainWindow->mToolBar, TB_CHECKBUTTON, IDC_BUTTON_PAUSE, FALSE);
    SendMessage(mainWindow->mToolBar, TB_ENABLEBUTTON, IDC_BUTTON_PAUSE, FALSE);
}

/**
 * 按键事件的响应函数。
 * @param mainWindow    主窗口
 * @param key           按键
 * @return 事件在此被处理则返回 TRUE，否则返回 FALSE
 */
static BOOL MainWindow_OnKeyPressed(MainWindow* mainWindow, UINT key) {
    return mainWindow->mGame->onKeyPressed(mainWindow->mGame, key);
}

/**
 * 得分事件的响应函数。
 * @param mainWindow    主窗口
 * @param score         得分
 */
static void MainWindow_OnScore(MainWindow* mainWindow, int score) {
    TCHAR text[STRING_BUF_LEN] = { 0 };
    TCHAR temp[STRING_BUF_LEN] = { 0 };

    LoadString(NULL, IDS_SCORE, text, STRING_BUF_LEN);
    _itot_s(score, temp, STRING_BUF_LEN, 10);
    _tcscat_s(text, STRING_BUF_LEN, temp);
    SendMessage(mainWindow->mStatusBar, SB_SETTEXT, 0, (LPARAM)text);
}

/**
 * 定时器事件的响应函数。
 * @param mainWindow    主窗口
 */
static void MainWindow_OnTimer(MainWindow* mainWindow) {
    mainWindow->mGame->onTimer(mainWindow->mGame);
}

/**
 * 窗口过程函数。
 * @param window    窗口
 * @param message   事件标识
 * @param wParam    事件相关信息
 * @param lParam    事件相关信息
 * @return 事件在此被处理则为 TRUE，否则为 FALSE
 */
static INT_PTR CALLBACK MainWindow_Proc(HWND window, UINT message, WPARAM wParam, LPARAM lParam) {
    MainWindow* mainWindow = (MainWindow*)GetWindowLongPtr(window, GWLP_USERDATA);
    LPNMHDR nmhdr = NULL;
    LPTOOLTIPTEXT tooltipText = NULL;
    WORD id = LOWORD(wParam);

    switch (message) {
        case UM_DIFFICULTY_UP:
            MainWindow_OnDifficultyUp(mainWindow, wParam);
            break;
        case UM_GAME_OVER:
            MainWindow_OnGameOver(mainWindow, wParam);
            break;
        case UM_SCORE:
            MainWindow_OnScore(mainWindow, wParam);
            break;
        case WM_ACTIVATE:
            MainWindow_OnActivate(mainWindow, wParam);
            break;
        case WM_CLOSE:
            MainWindow_Delete(mainWindow);
            break;
        case WM_COMMAND:
            switch (id) {
                case IDC_BUTTON_HELP:
                    MainWindow_OnButtonHelpClicked(mainWindow);
                    break;
                case IDC_BUTTON_MUSIC:
                    MainWindow_OnButtonMusicClicked(mainWindow);
                    break;
                case IDC_BUTTON_PAUSE:
                    MainWindow_OnButtonPauseClicked(mainWindow);
                    break;
                case IDC_BUTTON_START:
                    MainWindow_OnButtonStartClicked(mainWindow);
                    break;
            }
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        case WM_NOTIFY:
            nmhdr = (LPNMHDR)lParam;
            if (nmhdr->code == TTN_GETDISPINFO) {
                tooltipText = (LPTOOLTIPTEXT)lParam;
                switch (tooltipText->hdr.idFrom) {
                    case IDC_BUTTON_HELP:
                        LoadString(NULL, IDS_HELP, tooltipText->szText, STRING_BUF_LEN);
                        break;
                    case IDC_BUTTON_MUSIC:
                        LoadString(NULL, IDS_MUSIC, tooltipText->szText, STRING_BUF_LEN);
                        break;
                    case IDC_BUTTON_PAUSE:
                        LoadString(NULL, IDS_PAUSE, tooltipText->szText, STRING_BUF_LEN);
                        break;
                    case IDC_BUTTON_START:
                        LoadString(NULL, IDS_START, tooltipText->szText, STRING_BUF_LEN);
                        break;
                }
            }
            break;
        case WM_TIMER:
            MainWindow_OnTimer(mainWindow);
            break;
    }
    return FALSE;
}
